#include "../StdAfx.h"
#include "Folder.h"
#include "PropertyStoreFactory.h"

using namespace SevenZip;

CONST PROPERTYKEY CPropertyStoreFactory::CachedPropertyKeys[] =
{
	PKEY_ItemName,
	PKEY_ItemTypeText,
};

CONST CPropertyStoreFactory::PROP_INFO CPropertyStoreFactory::AllProperties[] =
{
	{ PKEY_ItemName,     0, &GetItemName },
	{ PKEY_ItemTypeText, 0, &GetItemTypeText },

	{ PKEY_Size,          CSevenZipArchiveItem::ITEMPROP_Size        },
	{ PKEY_TotalFileSize, CSevenZipArchiveItem::ITEMPROP_PackedSize  },

	{ PKEY_DateAccessed, CSevenZipArchiveItem::ITEMPROP_DateAccessed },
	{ PKEY_DateCreated,  CSevenZipArchiveItem::ITEMPROP_DateCreated  },
	{ PKEY_DateModified, CSevenZipArchiveItem::ITEMPROP_DateModified },
};

HRESULT CPropertyStoreFactory::GetItemName(CComPropVariant & Value) CONST
{
	HRESULT  hr = E_FAIL;
	CStringW str;

	if (SUCCEEDED(hr = _Item->GetName(str)))
	{
		Value = str;
	}

	return hr;
}

HRESULT CPropertyStoreFactory::GetItemTypeText(CComPropVariant & Value) CONST
{
	HRESULT  hr = E_FAIL;
	CStringW str;

	if (SUCCEEDED(hr = _Item->GetType(str)))
	{
		CComMemPtr<WCHAR> Result;

		if (SUCCEEDED(hr = ::PSFormatForDisplayAlloc(PKEY_ItemType, CComPropVariant(str), PDFF_DEFAULT, &Result)))
		{
			Value = Result;
		}
	}

	return hr;
}

STDMETHODIMP CPropertyStoreFactory::Initialize(CSevenZipFolder * Folder, SevenZip::CSevenZipArchiveItem * Item)
{
	if (((Folder == NULL) && (Item == NULL)) ||
		((Folder != NULL) && (Item != NULL)))
	{
		_Owner = Folder;
		_Item = Item;

		return S_OK;
	}

	return E_INVALIDARG;
}

STDMETHODIMP CPropertyStoreFactory::GetPropertyStoreToCache(REFIID InterfaceID, VOID * * Pointer)
{
	return GetPropertyStoreForKeys(CachedPropertyKeys,
	                               ARRAYSIZE(CachedPropertyKeys),
								   GPS_DEFAULT,
								   InterfaceID,
								   Pointer);
}

IFACEMETHODIMP CPropertyStoreFactory::GetPropertyStore(GETPROPERTYSTOREFLAGS Flags, IUnknown *, REFIID InterfaceID, VOID ** Pointer)
{
	return GetPropertyStoreForKeys(NULL, 0, Flags, InterfaceID, Pointer);
}

IFACEMETHODIMP CPropertyStoreFactory::GetPropertyStoreForKeys(CONST PROPERTYKEY *   Keys, 
															  UINT                  Count, 
															  GETPROPERTYSTOREFLAGS , 
															  REFIID                InterfaceID, 
															  VOID * *              Pointer)
{
	HRESULT hr = E_FAIL;

	if ((Count > 0) && (Keys != NULL))
	{
		CComMemPtr<PROP_INFO> PropertiesByKey;

		if (SUCCEEDED(hr = PropertiesByKey.Allocate(Count)))
		{
			for (unsigned k = 0; SUCCEEDED(hr) && (k < Count); k++)
			{
				PROP_INFO Info = { 0 };

				for (unsigned i = 0; SUCCEEDED(hr) && (i < ARRAYSIZE(AllProperties)); i++)
				{
					CONST PROP_INFO * ThisInfo = &AllProperties[i];

					if (ThisInfo->Property == Keys[k])
					{
						Info = *ThisInfo;
						break;
					}
				}

				PropertiesByKey[k] = Info;
			}
		}

		if (SUCCEEDED(hr))
		{
			hr = CreatePropertyStore(PropertiesByKey, Count, InterfaceID, Pointer);
		}
	}
	else
	{
		hr = CreatePropertyStore(AllProperties, ARRAYSIZE(AllProperties), InterfaceID, Pointer);
	}

	return hr;
}


HRESULT CPropertyStoreFactory::CreatePropertyStore(CONST PROP_INFO * Properties, UINT Count, REFIID InterfaceID, VOID * * Pointer)
{
	HRESULT hr = E_FAIL;
	CComPtr<IPropertyStore> Store;

	if ((_Owner != NULL) && (_Item != NULL))
	{
		hr = E_POINTER;

		if (Pointer != NULL)
		{
			if (SUCCEEDED(hr = ::PSCreateMemoryPropertyStore(IID_PPV_ARGS(&Store))))
			{
				for (UINT i = 0; SUCCEEDED(hr) && (i < Count); i++)
				{
					CONST PROP_INFO * Info = &Properties[i];

					if (Info->Property != PKEY_Null)
					{
						CComPropVariant Value;

						if (Info->Handler != NULL)
						{
							hr = (this->*Info->Handler)(Value);
						}
						else if (Info->PropID != 0)
						{
							hr = _Item->GetPropertyValue(Info->PropID, Value);
						}

						if (SUCCEEDED(hr))
						{
							hr = Store->SetValue(Info->Property, Value);
						}
					}
				}
			}

			if (SUCCEEDED(hr))
			{
				hr = Store->QueryInterface(InterfaceID, Pointer);
			}
		}
	}

	return hr;
}


BOOL CPropertyStoreFactory::IsCached(REFPROPERTYKEY Key)
{
	for (unsigned i = 0; i < ARRAYSIZE(CachedPropertyKeys); i++)
	{
		if (CachedPropertyKeys[i] == Key)
		{
			return TRUE;
		}
	}

	return FALSE;
}